#ifndef NANE_STACKSTRING_H
#   define  NANE_STACKSTRING_H

#   include "types.h"

#   include <algorithm>
#   include <cassert>
#   include <cstdio>
#   include <cstring>
#   include <cstdarg>

namespace nane
{
    template<uint32 N>
    class StackString
    {
    private:
        uint32 m_size;
        char m_buffer[N];
        uint8 m_formatInsertions;

    public:
        static const uint32 npos = 0xFFFFFFFF;
        
        StackString( )
            : m_size(0)
            , m_formatInsertions(0)
        {
            m_buffer[0] = 0;
        }

        StackString( const StackString& _str )
            : m_size(_str.m_size)
            , m_formatInsertions(0)
        {
            memcpy(m_buffer, _str.m_buffer, (m_size + 1) * sizeof(char));
        }
        
        template<uint32 N2>
        StackString( const StackString<N2>& _str )
            : m_size(0)
            , m_formatInsertions(0)
        {
            assign(_str.begin(), (_str.size() + 1) * sizeof(char));
        }
        
        StackString( const StackString& _str, uint32 _pos, uint32 _n = npos )
            : m_size(0)
            , m_formatInsertions(0)
        {
            assign(_str, _pos, _n);
        }
        
        StackString( const char* _s, uint32 _n )
            : m_size(0)
            , m_formatInsertions(0)
        {
            assign(_s, _n);
        }        

        StackString( const char* _s )
            : m_size(0)
            , m_formatInsertions(0)
        {
            assign(_s);
        }
        
        StackString( uint32 _n, char _c )
            : m_size(0)
            , m_formatInsertions(0)
        {
            
        }

        StackString( const char* _first, const char* _last )
            : m_size(0)
            , m_formatInsertions(0)
        {
            assign(_first, _last);
        }

        StackString& operator=( const StackString& _str )
        {
            return assign(_str);
        }

        StackString& operator=( const char* _s )
        {
            return assign(_s);
        }

        StackString& operator=( char _c )
        {
            return assign(1, _c);
        }

        StackString& assign( const StackString& _str )
        {
            m_size = _str.m_size;
            memcpy(m_buffer, _str.m_buffer, (m_size + 1) * sizeof(char));
            return *this;
        }

        StackString& assign( const StackString& _str, uint32 _pos, uint32 _n )
        {
            assert( _pos < _str.size() && "Position out of string" );
            if( _pos < _str.size() )
            {
                _n = (std::min)(_n, _str.size() - _pos);
                assign(_str.begin() + _pos, _n);
            }
            return *this;
        }

        StackString& assign( const char* _s, uint32 _n )
        {
            bool overflow = false;
            assert( _s != NULL && "NULL pointer" );
            if (_s == NULL)
            {
                return *this;
            }

            if (_n > N - 1)
            {
                assert( false && "Buffer overflow" );
                _n = N - 1;
                overflow = true;
            }

            if (_n > 0)
            {
                memcpy(m_buffer, _s, _n * sizeof(char));
                m_buffer[_n] = 0;
                m_size = _n;
            }
            else
            {
                m_buffer[0] = 0;
                m_size = 0;
            }

            if( overflow == true )
            {
                m_buffer[_n-1] = '~';
            }
            return *this;
        }

        StackString& assign( const char* _str )
        {
            return assign(_str, strlen(_str));
        }

        StackString& assign( uint32 _n, char _c )
        {
            bool overflow = false;
            if( _n > N - 1 )
            {
                assert( false && "Buffer overflow" );
                _n = N - 1;
            }

            memset(m_buffer, static_cast<int>(_c), _n * sizeof(char));

            m_size = _n;
            m_buffer[m_size] = 0;
            if( overflow == true )
                m_buffer[m_size-1] = '~';

            return *this;
        }

        StackString& assign(const char* _first, const char* _last)
        {
            assert(_first <= _last && "Invalid parameters");
            return assign(_first, static_cast<uint32>(_last - _first));
        }

        StackString& operator+=( const StackString& _str )
        {
            return append(_str);
        }

        StackString& operator+=( const char* _s )
        {
            return append(_s);
        }

        StackString& operator+=( char _c )
        {
            return append(_c);
        }

        StackString& append( const StackString& _str )
        {
            return append(_str.begin(), _str.size());
        }

        StackString& append( const StackString& _str, uint32 _pos, uint32 _n )
        {
            assert( _pos < _str.size() && "Position out of string" );
            if( _pos < _str.size() )
            {
                _n = (std::min)(_n, _str.size() - _pos);
                append(_str.begin() + _pos, _n);
            }
            return *this;
        }

        StackString& append( const char* _s, uint32 _n )
        {
            bool overflow = false;
            assert( _s != NULL && "NULL pointer" );
            if( _s == NULL )
            {
                return *this;
            }

            if( m_size + _n > N - 1 )
            {
                assert(false && "Buffer overflow");
                _n = N - m_size - 1;
                overflow = true;
            }

            if( _n > 0 )
            {
                memcpy(&m_buffer[m_size], _s, _n * sizeof(char));
                m_size += _n;
                m_buffer[m_size] = 0;
            }

            if( overflow == true )
            {
                m_buffer[m_size-1] = '~';
            }

            return *this;
        }

        StackString& append( const char* _str )
        {
            return append(_str, strlen(_str));
        }

        StackString& append( uint32 _n, char _c )
        {
            bool overflow = false;
            if( N - 1 - m_size < _n )
            {
                assert(false && "Buffer overflow");
                _n = N - 1 - m_size;
                overflow = true;
            }

            memset(&m_buffer[m_size], static_cast<int>(_c), _n * sizeof(char));
            m_size += _n;
            m_buffer[m_size] = 0;
            if( overflow == true )
            {
                m_buffer[m_size-1] = '~';
            }
            return *this;
        }

        StackString& append( const char* _first, const char* _last )
        {
            assert(_first <= _last && "Invalid parameters");
            return append(_first, static_cast<uint32>(_last - _first));
        }

        StackString& insert( uint32 _pos1, const StackString& _str )
        {
            return insert(_pos1, _str, 0, _str.size());
        }

        StackString& insert( uint32 _pos1, const StackString& _str, uint32 _pos2, uint32 _n )
        {
            if (_pos2 > _str.size())
            {
                assert(false && "Right offset outside string data");
                return *this;
            }
            return insert(_pos1, _str.begin() + _pos2, _n);
        }

        StackString& insert( uint32 _pos1, const char* _s, uint32 _n )
        {
            bool overflow = false;
            if( _s >= m_buffer && _s < &m_buffer[m_size] )
            {
                assert(false && "Input String overlaps buffer");
            }

            if( _pos1 > m_size )
            {
                assert(false && "Wrong insert position");
                return *this;
            }

            if( m_size + _n > N - 1 )
            {
                assert(false && "Buffer overflow");
                _n = N - m_size - 1;
                overflow = true;
            }

            if( _n > 0 )
            {
                memmove(&m_buffer[_pos1 + _n], &m_buffer[_pos1], (m_size - _pos1 + 1) * sizeof(char));
                memcpy(&m_buffer[_pos1], _s, _n * sizeof(char));
                m_size += _n;
            }
            if( overflow == true )
            {
                m_buffer[m_size-1] = '~';
            }

            return *this;
        }

        StackString& insert( uint32 _pos1, const char* _s )
        {
            return insert(_pos1, _s, strlen(_s));
        }

        StackString& insert( uint32 _pos1, uint32 _n, char _c )
        {
            bool overflow = false;
            if( _pos1 > m_size )
            {
                assert(false && "Wrong insert position");
                return *this;
            }

            if( m_size + _n > N - 1 )
            {
                assert(false && "Buffer overflow");
                _n = N - m_size - 1;
                overflow = true;
            }

            if( _n > 0 )
            {
                memmove(&m_buffer[_pos1 + _n], &m_buffer[_pos1], (m_size - _pos1 + 1) * sizeof(char));
                memset(&m_buffer[_pos1], static_cast<int>(_c), _n * sizeof(char));
                m_size += _n;
            }

            if( overflow == true )
            {
                m_buffer[m_size - 1] = '~';
            }

            return *this;
        }

        char* insert( char* _p, char _c )
        {
            if( _p < m_buffer || _p >= &m_buffer[m_size] )
            {
                assert( false && "Invalid insertion iterator" );
                return end();
            }

            if( m_size + 1 > N - 1 )
            {
                assert( false && "Buffer overflow" );
                m_buffer[m_size-1] = '~';
                return end();
            }

            memmove(_p+1, _p, &(m_buffer[m_size+1])-_p);
            ++m_size;
            *_p = _c;
            return _p;
        }

        void insert( char* _p, uint32 _n, char _c )
        {
            bool overflow = false;
            if( _p < m_buffer || _p >= &m_buffer[m_size] )
            {
                assert( false && "Invalid insertion iterator" );
                return;
            }

            if( m_size + _n > N - 1 )
            {
                assert( false && "Buffer overflow" );
                _n = N - m_size - 1;
                overflow = true;
            }

            if( _n > 0 )
            {
                memmove(_p+_n, _p, &(m_buffer[m_size+1])-_p);
                memset(_p, static_cast<int>(_c), _n * sizeof(char));
                m_size += _n;
            }

            if( overflow == true )
            {
                m_buffer[m_size-1] = '~';
            }
        }

        void insert( char* _p, const char* _first, const char* _last )
        {
            if( _p < m_buffer || _p >= &m_buffer[m_size] )
            {
                assert( false && "Invalid insertion iterator" );
                return;
            }

            uint32 pos = (_p - begin()) / sizeof(char);
            insert(pos, _first, (_first - _last) / sizeof(char));
        }

        StackString& replace( uint32 _pos1, uint32 _n1, const StackString& _str )
        {
            return replace(_pos1, _n1, _str, 0, _str.size());
        }

        StackString& replace( char* _i1, char* _i2, const StackString& _str )
        {
            if( _i1 < m_buffer || _i1 >= end() || _i2 < m_buffer || _i2 > end() )
            {
                assert( false && "Invalid insertion iterator" );
                return *this;
            }
            return replace((_i1 - m_buffer) / sizeof(char), (_i2 - _i1) / sizeof(char), _str);
        }

        StackString& replace( uint32 _pos1, uint32 _n1, const StackString& _str, uint32 _pos2, uint32 _n2 )
        {
            return replace(_pos1, _n1, _str.begin() + _pos2, _n2);
        }

        StackString& replace( uint32 _pos1, uint32 _n1, const char* _s, uint32 _n2 )
        {
            if( _s >= m_buffer && _s < &m_buffer[m_size] )
            {
                assert( false && "Input String overlaps buffer" );
            }

            if( _pos1 > m_size )
            {
                assert( false && "Wrong replace position" );
                return *this;
            }

            if( _n2 <= _n1 )
            {
                memcpy(&m_buffer[_pos1], _s, _n2 * sizeof(char));
                memmove(&m_buffer[_pos1 + _n2], &m_buffer[_pos1 + _n1], (m_size - _pos1 - _n1 + 1) * sizeof(char));
                m_size -= _n1 - _n2;
            }
            else
            {
                bool overflow = false;
                uint32 diff = _n2 - _n1;

                if( m_size + diff > N - 1 )
                {
                    assert( false && "Buffer overflow" );
                    overflow = true;
                    _n2 = _n1;
                    diff = 0;
                }

                memmove(&m_buffer[_pos1 + _n2], &m_buffer[_pos1 + _n1], (m_size - _pos1 - _n1 + 1) * sizeof(char));
                memcpy(&m_buffer[_pos1], _s, _n2 * sizeof(char));
                m_size += diff;
                if( overflow == true )
                {
                    m_buffer[m_size-1] = '~';
                }
            }

            return *this;
        }

        StackString& replace( uint32 _pos1, uint32 _n1, const char* _s )
        {
            return replace(_pos1, _n1, _s, strlen(_s));
        }

        StackString& replace( char* _i1, char* _i2, const char* _s )
        {
            if( _i1 < m_buffer || _i1 >= end() || _i2 < m_buffer || _i2 > end() )
            {
                assert( false && "Invalid insertion iterator" );
                return *this;
            }
            return replace((_i1 - m_buffer) / sizeof(char), (_i2 - _i1) / sizeof(char), _s);
        }

        StackString& replace( uint32 _pos1, uint32 _n1, uint32 _n2, char _c )
        {
            if( _pos1 > m_size )
            {
                assert( false && "Wrong replace position" );
                return *this;
            }

            if( _n2 <= _n1 )
            {
                memset(&m_buffer[_pos1], static_cast<int>(_c), _n2 * sizeof(char));
                memmove(&m_buffer[_pos1 + _n2], &m_buffer[_pos1 + _n1], (m_size - _pos1 - _n1 + 1) * sizeof(char));
                m_size -= _n1 - _n2;
            }
            else
            {
                bool overflow = false;
                uint32 diff = _n2 - _n1;

                if( m_size + diff > N - 1 )
                {
                    assert( false && "Buffer overflow" );
                    overflow = true;
                    _n2 = _n1;
                    diff = 0;
                }

                memmove(&m_buffer[_pos1 + _n2], &m_buffer[_pos1 + _n1], (m_size - _pos1 - _n1 + 1) * sizeof(char));
                memset(&m_buffer[_pos1], static_cast<int>(_c), _n2 * sizeof(char));
                m_size += diff;
                if( overflow == true )
                {
                    m_buffer[m_size-1] = '~';
                }
            }

            return *this;
        }

        StackString& replace( char* _i1, char* _i2, uint32 _n2, char _c )
        {
            if( _i1 < m_buffer || _i1 >= end() || _i2 < m_buffer || _i2 > end() )
            {
                assert( false && "Invalid insertion iterator" );
                return *this;
            }
            return replace((_i1 - m_buffer) / sizeof(char), (_i2 - _i1) / sizeof(char), _n2, _c);
        }

        StackString& replace( char* _i1, char* _i2, const char* _j1, const char* _j2 )
        {
            return replace(_i1, _i2, _j1, (_j2-_j1) / sizeof(char));
        }

        StackString& erase( uint32 _pos = 0, uint32 _n = npos )
        {
            if( _pos >= m_size )
            {
                //assert(false && "Wrong erase position");
                return *this;
            }

            _n = (std::min)(_n, m_size - _pos);
            if (_n > 0)
            {
                memmove(&m_buffer[_pos], &m_buffer[_pos + _n], (m_size - (_pos + _n - 1)) * sizeof(char));
                m_size -= _n;
            }

            return *this;
        }

        char* erase( char* _position )
        {
            return erase( _position, _position + 1 );
        }

        char* erase( char* _first, char* _last )
        {
            if( _first < begin() || _first >= end() || _last < begin() || _last > end() )
            {
                assert( false && "Invalid erase range" );
                return end();
            }

            uint32 pos = (_first - begin()) / sizeof(char);
            erase(pos, (_last - _first)/sizeof(char));
            if( _first >= end() )
                _first = end();
            return _first;
        }

        void clear( )
        {
            m_size = 0;
            m_buffer[0] = 0;
        }

        char& operator[](uint32 _index)
        {
            assert(_index <= m_size && "Index out of range");
            return m_buffer[_index];
        }

        const char& operator[](uint32 _index) const
        {
            assert(_index <= m_size && "Index out of range");
            return m_buffer[_index];
        }

        const char& at ( uint32 _pos ) const
        {
            return (*this)[_pos];
        }

        char& at ( uint32 _pos )
        {
            return (*this)[_pos];
        }

        uint32 size() const
        {
            return m_size;
        }

        uint32 length() const
        {
            return m_size;
        }

        bool empty() const
        {
            return m_size == 0;
        }

        const char* c_str() const
        {
            return m_buffer;
        }

        const char* begin() const
        {
            return m_buffer;
        }

        char* begin()
        {
            return m_buffer;
        }

        const char* end() const
        {
            return &(m_buffer[m_size]);
        }

        char* end()
        {
            return &(m_buffer[m_size]);
        }

        static uint32 capacity()
        {
            return N;
        }

        uint32 find( char _c, uint32 _pos = 0 ) const
        {
            if( _pos >= m_size )
            {
                assert( false && "Position out of string" );
                return npos;
            }
            for (uint32 i = 0; i < m_size; ++i)
            {
                if( m_buffer[i] == _c )
                {
                    return i;
                }
            }
            return npos;
        }

        uint32 find( const StackString& _str, uint32 _pos = 0 ) const
        {
            return find(_str.c_str(), _pos);
        }

        uint32 find( const char* _s, uint32 _pos, uint32 _n ) const
        {
            if( _pos >= m_size )
            {
                assert( false && "Position out of string" );
                return npos;
            }

            const char* p = &(m_buffer[_pos]);
            while( p != NULL )
            {
                const char* p = strstr(p, _s);
                if( p != NULL && !strncmp(p, _s, _n) )
                    return (p - m_buffer)/sizeof(char);
            }
            return npos;
        }

        uint32 find( const char* _s, uint32 _pos = 0 ) const
        {
            if( _pos >= m_size )
            {
                assert( false && "Position out of string" );
                return npos;
            }

            const char* p = strstr(&(m_buffer[_pos]), _s);
            return p == NULL ? npos : (p - m_buffer)/sizeof(char);
        }

        uint32 copy( char* _s, uint32 _n, uint32 _pos = 0 ) const
        {
            assert( _s != NULL && "Invalid destination string" );
            if( _s != NULL && _n > 0 )
            {
                _n = (std::min)(_n, m_size-_pos);
                memcpy(_s, m_buffer, _n * sizeof(char));
            }
            return _n;
        }

        static uint32 max_size( )
        {
            return N;
        }

        void push_back( char _c )
        {
            append(_c);
        }

        void swap( StackString& _str )
        {
            std::swap( m_buffer, _str.m_buffer );
            std::swap( m_size, _str.m_size );
        }

        int compare( const StackString& _str ) const
        {
            return compare(_str.c_str());
        }

        int compare( const char* _s ) const
        {
            return strcmp(m_buffer, _s);
        }

        int compare( uint32 _pos1, uint32 _n1, const StackString& _str ) const
        {
            return compare(_pos1, _n1, _str.c_str());
        }

        int compare( uint32 _pos1, uint32 _n1, const char* _s ) const
        {
            if( _pos1 >= m_size )
            {
                assert( false && "Position out of string" );
                return -1;
            }
            return strncmp(&(m_buffer[_pos1]), _s, _n1);
        }

        int compare( uint32 _pos1, uint32 _n1, const StackString& _str, uint32 _pos2, uint32 _n2 ) const
        {
            if( _pos2 >= _str.size() )
            {
                assert( false && "Position out of string" );
                return 1;
            }
            return compare(_pos1, _n1, &(_str[_pos2]), _n2);
        }

        int compare( uint32 _pos1, uint32 _n1, const char* _s, uint32 _n2 ) const
        {
            return compare( _pos1, (std::min)(_n1, _n2), _s);
        }

        void resize( uint32 _n, char _c )
        {
            if( _n < m_size )
            {
                m_size = _n;
            }
            else
            {
                append(m_size - _n, _c);
            }
        }

        void resize( uint32 _n )
        {
            resize(_n, char());
        }

        StackString& operator<<( const char* _rhs )
        {
            if( m_formatInsertions >= 9 )
            {
                assert( false && "Max insertions 9" );
                return *this;
            }
            ++m_formatInsertions;
            char replaceString[3] = "%0";
            replaceString[1] = '0' + m_formatInsertions;
            uint32 pos = 0;
            while( (pos = find(replaceString, pos)) != npos )
            {
                uint32 n = strlen(_rhs);
                replace(pos, 2, _rhs, n);
                pos = (std::min)(pos + n, m_size -1);
            }
            return *this;
        }

        template<uint32 N2>
        StackString& operator<<( const StackString<N2>& _rhs )
        {
            return operator<<(_rhs.c_str());
        }

        StackString& operator<<( int32 _rhs )
        {
            char buffer[16] = {0};
            std::sprintf(buffer, "%d", _rhs);
            return (*this)<<buffer;
        }

        StackString& operator<<( long int _rhs )
        {
            return operator<<(static_cast<int32>(_rhs));
        }

        StackString& operator<<( uint32 _rhs )
        {
            char buffer[16] = {0};
            std::sprintf(buffer, "%u", _rhs);
            return (*this)<<buffer;
        }

        StackString& operator<<( int64 _rhs )
        {
            char buffer[16] = {0};
#ifdef _WIN32
            std::sprintf(buffer, "%I64d", _rhs);
#else
            std::sprintf(buffer, "%lld", _rhs);
#endif       
            return (*this)<<buffer;
        }

        StackString& operator<<( uint64 _rhs )
        {
            char buffer[16] = {0};
#ifdef _WIN32
            std::sprintf(buffer, "%I64u", _rhs);
#else
            std::sprintf(buffer, "%llu", _rhs);
#endif       
            return (*this)<<buffer;
        }

        StackString& operator<<( float _rhs )
        {
            char buffer[16] = {0};
            std::sprintf(buffer, "%f", _rhs);
            return (*this)<<buffer;
        }

        StackString& operator<<( bool _rhs )
        {
            const char* s = _rhs ? "true" : "false";
            return (*this)<<s;
        }
        
        StackString& operator<<( void* _rhs )
        {
            char buffer[sizeof(void*)/4+3];
            std::sprintf(buffer, "0x%x", _rhs);
            return (*this)<<buffer;
        }

        void format( const char* _format, ... )
        {
            va_list vargs;
            va_start(vargs, _format);
            m_size = std::vsprintf(m_buffer, _format, vargs);
            va_end(vargs);
        }
    };

    template<uint32 N>
    StackString<N> operator+( char _lhs, const StackString<N>& _rhs )
    {
        return StackString<N>(_lhs) += _rhs;
    }

    template<uint32 N>
    StackString<N> operator+( const StackString<N>& _lhs, char _rhs )
    {
            return StackString<N>(_lhs) += _rhs;
    }

    template<uint32 N>
    StackString<N> operator+( const char* _lhs, const StackString<N>& _rhs )
    {
            return StackString<N>(_lhs) += _rhs;
    }

    template<uint32 N>
    StackString<N> operator+( const StackString<N>& _lhs, const char* _rhs )
    {
            return StackString<N>(_lhs) += _rhs;
    }

    template<uint32 N>
    StackString<N> operator+( const StackString<N>& _lhs, const StackString<N>& _rhs )
    {
        return StackString<N>(_lhs) += _rhs;
    }

    template<uint32 N>
    bool operator==( const char* _lhs, const StackString<N>& _rhs )
    {
        uint32 lhs_size = strlen(_lhs);
        if (lhs_size != _rhs.size())
        {
            return false;
        }
        return memcmp(_lhs, _rhs.getBuffer(), lhs_size * sizeof(char)) == 0;
    }

    template<uint32 N>
    bool operator==( const StackString<N>& _lhs, const char* _rhs )
    {
        return _rhs == _lhs;
    }

    template<uint32 N, uint32 N2>
    bool operator==( const StackString<N>& _lhs, const StackString<N2>& _rhs )
    {
        if (_lhs.size() != _rhs.size())
        {
            return false;
        }
        return memcmp(_lhs.getBuffer(), _rhs.getBuffer(), _lhs.size()) == 0;
    }

    template<uint32 N>
    bool operator!=( const char* _lhs, const StackString<N>& _rhs )
    {
        return !(_lhs == _rhs);
    }

    template<uint32 N>
    bool operator!=( const StackString<N>& _lhs, const char* _rhs )
    {
        return !(_lhs == _rhs);
    }

    template<uint32 N, uint32 N2>
    bool operator!=( const StackString<N>& _lhs, const StackString<N2>& _rhs )
    {
        return !(_lhs == _rhs);
    }

    template<uint32 N>
    bool operator<( const char* _lhs, const StackString<N>& _rhs )
    {
        return strcmp(_lhs, _rhs.getBuffer()) < 0;
    }

    template<uint32 N>
    bool operator<( const StackString<N>& _lhs, const char* _rhs )
    {
        return strcmp(_lhs.getBuffer(), _rhs) < 0;
    }

    template<uint32 N, uint32 N2>
    bool operator<( const StackString<N>& _lhs, const StackString<N2>& _rhs )
    {
        return strcmp(_lhs.getBuffer(), _rhs.getBuffer()) < 0;
    }

    template<uint32 N>
    bool operator>( const char* _lhs, const StackString<N>& _rhs )
    {
        return _rhs < _lhs;
    }

    template<uint32 N>
    bool operator>( const StackString<N>& _lhs, const char* _rhs )
    {
        return _rhs < _lhs;
    }

    template<uint32 N, uint32 N2>
    bool operator>( const StackString<N>& _lhs, const StackString<N2>& _rhs )
    {
        return _rhs < _lhs;
    }

    template<uint32 N>
    bool operator<=( const char* _lhs, const StackString<N>& _rhs )
    {
        return !(_rhs < _lhs);
    }

    template<uint32 N>
    bool operator<=( const StackString<N>& _lhs, const char* _rhs )
    {
        return !(_rhs < _lhs);
    }

    template<uint32 N, uint32 N2>
    bool operator<=( const StackString<N>& _lhs, const StackString<N2>& _rhs )
    {
        return !(_rhs < _lhs);
    }

    template<uint32 N>
    bool operator>=( const char* _lhs, const StackString<N>& _rhs )
    {
        return !(_lhs < _rhs);
    }

    template<uint32 N>
    bool operator>=( const StackString<N>& _lhs, const char* _rhs )
    {
        return !(_lhs < _rhs);
    }

    template<uint32 N, uint32 N2>
    bool operator>=( const StackString<N>& _lhs, const StackString<N2>& _rhs )
    {
        return !(_lhs < _rhs);
    }

}   // namespace nane

#endif	// NANE_STACKSTRING_H
